#include "stdafx.h"
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <asm/byteorder.h>
#include <linux/netfilter.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <sys/socket.h>
#include "checksum.h"
#include "ip_pack_queue.h"

static int gnchecketh		= 0;

/*
 * 包回调函数
 */
int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg
		, struct nfq_data *nfa, void *data)
{
	u_int32_t							id				= 0;
	struct nfqnl_msg_packet_hdr*		ph;
	unsigned char*						pdata			= NULL;
	int									pdata_len		= 0;
	struct iphdr*						iphdrp			= NULL;
	struct tcphdr*						tcphdrp;
	int									eth				= 0;
	char								szShow[32]		= {0};
	char*								pHost			= NULL;
	struct nfqnl_msg_packet_hw*			phw;

	ph = nfq_get_msg_packet_hdr(nfa);
	if( ph )
	{
		id = ntohl(ph->packet_id);
	}

	pdata_len = nfq_get_payload(nfa, (char**)&pdata);
	if( -1 == pdata_len )
	{
		pdata_len = 0;
	}

	iphdrp = (struct iphdr*)pdata;
	if( NULL == iphdrp )
	{
		printf("error: nfq_set_verdict_mark\n");
		goto cb_end;
	}

	if( IPPROTO_TCP != iphdrp->protocol )
	{
		goto cb_end;
	}
	// 获取来源网卡
	eth = nfq_get_physoutdev(nfa);
	if(gnchecketh != eth)
	{
		// 不是转发送到外网的数据包
		goto cb_end;
	}
	// 判断数据标志
	tcphdrp	= (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl << 2));
	// 分析连接协议
	strncpy(szShow, (char*)tcphdrp + (tcphdrp->doff << 2), 16);
	if( strncasecmp(szShow, "GET\x20", 4) != 0 )
	{
		goto cb_end;
	}
	// 打印MAC
	phw = nfq_get_packet_hw(nfa);
	printf("%02hx-%02hx-%02hx-%02hx-%02hx-%02hx ",
			phw->hw_addr[0], phw->hw_addr[1], phw->hw_addr[2],
			phw->hw_addr[3], phw->hw_addr[4], phw->hw_addr[5]);
	// 发现可凝HTTP包
	ip_pack_add(pdata, pdata_len);

	return nfq_set_verdict_mark(qh, id, NF_DROP, 1, 0, NULL);
cb_end:
	return nfq_set_verdict_mark(qh, id, NF_REPEAT/*NF_ACCEPT*/, 1, (u_int32_t)pdata_len, pdata);
}
/*
 * 测试主函数
 */
int nfq_start(int ethout)
{
	struct nfq_handle*		h;
	struct nfq_q_handle*	qh;
//	struct nfnl_handle*		nh;
	int						fd;
	int						rv;
	char					buf[40960];
	int						qid				= 8603;

	gnchecketh = ethout;
	// 打开监控驱动
	h = nfq_open();
	if( !h )
	{
		perror("nfq_open: ");
		exit(1);
	}

	if( nfq_unbind_pf(h, AF_INET) < 0 )
	{
		perror("nfq_unbind_pf: ");
		exit(1);
	}

	if( nfq_bind_pf(h, AF_INET) < 0 )
	{
		perror("nfq_bind_pf:");
		exit(1);
	}

	qh = nfq_create_queue(h, qid, &cb, NULL);
	if( !qh )
	{
		perror("nfq_create_queue:");
		exit(1);
	}

	if(nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0)
	{
		perror("nfq_set_mode:");
		exit(1);
	}

//	nh = nfq_nfnlh(h);
//	fd = nfnl_fd(nh);
	fd = nfq_fd(h);

	while((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0)
	{
		nfq_handle_packet(h, buf, rv);
	}
	printf("!!!error: recv %s\n", (char *)strerror(errno));
	nfq_destroy_queue(qh);

	nfq_close(h);
	exit(-1);
	return 0;
}

